package me.illtamer.rpc.transport.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import me.illtamer.rpc.codec.CommonDecoder;
import me.illtamer.rpc.codec.CommonEncoder;
import me.illtamer.rpc.hook.ShutdownHook;
import me.illtamer.rpc.provider.ServiceProviderImpl;
import me.illtamer.rpc.register.NacosServiceRegistry;
import me.illtamer.rpc.transport.AbstractRpcServer;
import me.illtamer.serializer.CommonSerializer;

import java.util.concurrent.TimeUnit;

public class NettyServer extends AbstractRpcServer {

    private final CommonSerializer serializer;

    public NettyServer(String host, int port) {
        this(host, port, DEFAULT_SERIALIZER);
    }

    public NettyServer(String host, int port, int serializerCode) {
        super.host = host;
        super.port = port;
        super.serviceRegistry = new NacosServiceRegistry();
        super.serviceProvider = new ServiceProviderImpl();
        this.serializer = CommonSerializer.getByCode(serializerCode);
        scanServices(); // 自动注册服务
    }

    @Override
    public void start() {
        // 添加注销服务的钩子，服务端关闭时执行
        ShutdownHook.SHUTDOWN_HOOK.addClearAllHook();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ChannelFuture future = new ServerBootstrap()
                    .group(boss, worker)
                    // 服务端接受连接的最大队列长度
                    .option(ChannelOption.SO_BACKLOG, 256)
                    // TCP的心跳机制，默认的心跳间隔是7200s即2小时
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 表禁用Nagle算法，减小传输延迟
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS))
                                    .addLast(new CommonEncoder(serializer))
                                    .addLast(new CommonDecoder())
                                    .addLast(new NettyServerHandler());
                        }
                    })
                    .bind(host, port)
                    .sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("启动服务器时有错误发生", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

}
